home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 41
/
Amiga Format CD41 (1999-06)(Future Publishing)(GB)[!][issue 1999-07].iso
/
-seriously_amiga-
/
programming
/
other
/
gtlayout
/
source
/
ltp_tabclass.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-04-19
|
16KB
|
766 lines
/*
** GadTools layout toolkit
**
** Copyright © 1993-1998 by Olaf `Olsen' Barthel
** Freely distributable.
**
** :ts=4
*/
#ifndef _GTLAYOUT_GLOBAL_H
#include "gtlayout_global.h"
#endif
/*****************************************************************************/
#include <intuition/classes.h>
#include <exec/memory.h>
#include <hardware/blit.h>
#include <clib/alib_protos.h> /* For Coerce/Do/DoSuperMethod */
#include <stdarg.h>
/*****************************************************************************/
#include "Assert.h"
#ifdef DO_TAB_KIND /* Support code */
#define TIA_Labels (TAG_USER+0x90000)
#define TIA_Font (TAG_USER+0x90001)
#define TIA_Screen (TAG_USER+0x90002)
#define TIA_Index (TAG_USER+0x90003)
#define TIA_DrawInfo (TAG_USER+0x90004)
#define TIA_SizeType (TAG_USER+0x90005)
STATIC VOID
DrawCap(struct RastPort *RPort,LONG Left,LONG Top,LONG Width,LONG Height,BOOL Flip)
{
LONG x,y,da,MidX,MidY,r,Full,Push,Mult;
Full = Height;
Height = Width;
MidX = Left;
MidY = Top + Height - 1;
r = Height - 1;
x = 0;
y = r;
da = r - 1;
if(Flip)
{
Push = Width - 1;
Mult = -1;
}
else
{
Push = 0;
Mult = 1;
}
do
{
if(da < 0)
{
y--;
da += y * 2;
}
WritePixel(RPort,Left + Push + Mult * (x + MidX - Left),-y + MidY);
WritePixel(RPort,Left + Push + Mult * (y + MidX - Left),-x + MidY);
da -= (1 + x * 2);
x++;
}
while(x <= y);
Left += Width - 1 - Push;
LTP_DrawLine(RPort,Left,Top + Height,Left,Top + Full - 1);
}
STATIC VOID
RenderTabs(struct RastPort *RPort,struct Gadget *gadget,TabInfo *Info,UWORD *Pens,LONG Pull)
{
LONG Width,Height;
LONG i;
LONG Pen;
Width = Info->TabWidth;
Height = Info->TabHeight;
SetRast(&Info->RPort,Pens[BACKGROUNDPEN]);
for(i = 0 ; i < 4 ; i++)
{
if(i & 1)
{
if(Pens[SHINEPEN] == Pens[SHADOWPEN])
Pen = BACKGROUNDPEN;
else
Pen = SHADOWPEN;
}
else
Pen = SHINEPEN;
LTP_SetAPen(&Info->RPort,Pens[Pen]);
LTP_DrawLine(&Info->RPort,0,Height - 1 - i,gadget->Width - 1 - Info->Thick * i,Height - 1 - i);
}
for(i = Info->Count - 1 ; i >= 0 ; i--)
{
if(i != Info->Current)
BltMaskBitMapRastPort(Info->Tabs[i].BitMap,0,0,&Info->RPort,Info->Tabs[i].Left,4,Width,Height - 6,ABC|ABNC|ANBC,Info->Mask);
}
BltMaskBitMapRastPort(Info->Tabs[Info->Current].BitMap,0,0,&Info->RPort,Info->Tabs[Info->Current].Left,0,Width,Height - Pull,ABC|ABNC|ANBC,Info->Mask);
WaitBlit();
BltBitMapRastPort(Info->BitMap,0,0,RPort,gadget->LeftEdge,gadget->TopEdge + gadget->Height - (Info->TabHeight + 2),gadget->Width,Info->TabHeight,0xC0);
}
STATIC VOID
SetMethod(struct IClass *class,struct Gadget *gadget,struct opSet *SetInfo)
{
TabInfo *Info = INST_DATA(class,gadget);
struct TagItem *Tag;
BOOL NeedRefresh = FALSE;
BOOL Disabled;
Disabled = (BOOL)((gadget->Flags & GFLG_DISABLED) != 0);
if(Tag = FindTagItem(GA_Disabled,SetInfo->ops_AttrList))
{
if(Tag->ti_Data && !Disabled || !Tag->ti_Data && Disabled)
NeedRefresh = TRUE;
}
if(Tag = FindTagItem(TIA_Index,SetInfo->ops_AttrList))
{
LONG Index = Tag->ti_Data;
if(Index >= Info->Count)
Index = Info->Count - 1;
if(Index != Info->Current)
{
Info->Initial = Info->Current = Index;
NeedRefresh = TRUE;
}
}
if(NeedRefresh)
{
struct RastPort *RPort;
if(RPort = ObtainGIRPort(SetInfo->ops_GInfo))
{
DoMethod((Object *)gadget,GM_RENDER,SetInfo->ops_GInfo,RPort,GREDRAW_REDRAW);
ReleaseGIRPort(RPort);
}
}
}
STATIC ULONG
RenderMethod(struct IClass *class,struct Gadget *gadget,struct gpRender *RenderInfo)
{
TabInfo *Info = INST_DATA(class,gadget);
RenderTabs(RenderInfo->gpr_RPort,gadget,Info,RenderInfo->gpr_GInfo->gi_DrInfo->dri_Pens,RenderInfo->gpr_Redraw == GREDRAW_UPDATE ? 2 : 0);
return(TRUE);
}
STATIC VOID
DisposeMethod(struct IClass *class,struct Gadget *gadget,Msg msg)
{
TabInfo *Info = INST_DATA(class,gadget);
if(Info->Mask || Info->Tabs || Info->BitMap)
WaitBlit();
if(Info->Mask)
{
FreeRaster(Info->Mask,Info->TabWidth,Info->TabHeight);
}
if(Info->Tabs)
{
LONG i;
for(i = 0 ; i < Info->Count ; i++)
LTP_DeleteBitMap(Info->Tabs[i].BitMap,TRUE);
FreeVec(Info->Tabs);
}
LTP_DeleteBitMap(Info->BitMap,FALSE);
}
STATIC ULONG
NewMethod(struct IClass *class,struct Gadget *gadget,struct opSet *SetInfo)
{
if(gadget = (struct Gadget *)DoSuperMethodA(class,(Object *)gadget,(Msg)SetInfo))
{
TabInfo *Info = INST_DATA(class,gadget);
struct TagItem *Tag,*TagList = SetInfo->ops_AttrList;
struct TextAttr *FontAttr;
LONG Width,Height;
struct DrawInfo *DrawInfo;
STRPTR *Labels;
struct Screen *Screen;
Width = 0;
Height = 0;
FontAttr = NULL;
DrawInfo = NULL;
Labels = NULL;
Screen = NULL;
memset(Info,0,sizeof(TabInfo));
while(Tag = NextTagItem(&TagList))
{
switch(Tag->ti_Tag)
{
case GA_Width:
Width = Tag->ti_Data;
break;
case GA_Height:
Height = Tag->ti_Data;
break;
case TIA_Labels:
Labels = (STRPTR *)Tag->ti_Data;
break;
case TIA_Font:
FontAttr = (struct TextAttr *)Tag->ti_Data;
break;
case TIA_Screen:
Screen = (struct Screen *)Tag->ti_Data;
break;
case TIA_Index:
Info->Current = Tag->ti_Data;
break;
case TIA_DrawInfo:
DrawInfo = (struct DrawInfo *)Tag->ti_Data;
break;
}
}
if(Labels)
{
while(Labels[Info->Count])
Info->Count++;
}
if(Screen && DrawInfo && FontAttr && Width && Height && Labels && Info->Count)
{
struct TextFont *Font;
if(Font = OpenFont(FontAttr))
{
struct RastPort *RPort = &Info->RPort;
InitRastPort(RPort);
SetFont(RPort,Font);
if(Height >= RPort->TxHeight + 11)
{
LONG i,Len,MaxWidth,Remain;
LONG Lean;
if(Info->Current < 0)
Info->Current = 0;
else
{
if(Info->Current >= Info->Count)
Info->Current = Info->Count - 1;
}
Lean = (TextLength(RPort,"O",1) + 1) / 2;
Info->Thick = (DrawInfo->dri_Resolution.Y + DrawInfo->dri_Resolution.X - 1) / DrawInfo->dri_Resolution.X;
if(Info->Thick < 1)
Info->Thick = 1;
for(i = MaxWidth = 0 ; i < Info->Count ; i++)
{
if((Len = TextLength(RPort,Labels[i],strlen(Labels[i]))) > MaxWidth)
MaxWidth = Len;
}
MaxWidth = Info->Thick + (Lean + Info->Thick - 1 + Info->Thick + MaxWidth + Info->Thick + Lean + Info->Thick - 1) + Info->Thick;
Remain = (Width - MaxWidth - 5 * Info->Thick) / (Info->Thick * 4);
if(Remain >= Info->Count - 1)
{
if(Info->Tabs = (TabEntry *)AllocVec(sizeof(TabEntry) * Info->Count,MEMF_ANY|MEMF_CLEAR))
{
STATIC const BYTE PenNumbers[] =
{
BACKGROUNDPEN,
SHINEPEN,
SHADOWPEN,
TEXTPEN
};
struct BitMap Mask;
LONG Depth;
LONG MaxPen;
UWORD *Pens = DrawInfo->dri_Pens;
BOOL GotIt = TRUE;
memset(&Mask,0,sizeof(Mask));
for(i = 0, MaxPen = -1 ; i < sizeof(PenNumbers) ; i++)
{
if(Pens[PenNumbers[i]] > MaxPen)
MaxPen = Pens[PenNumbers[i]];
}
Depth = 8; /* For the sake of the compiler initialize this. */
for(i = 1 ; i <= 8 ; i++)
{
if(MaxPen < (1 << i))
{
Depth = i;
break;
}
}
Info->TabWidth = MaxWidth;
Info->TabHeight = 4 + RPort->TxHeight + 5;
InitBitMap(&Mask,1,Info->TabWidth,Info->TabHeight);
Mask.Planes[1] = NULL;
for(i = 0 ; GotIt && i < 2 ; i++)
{
if(!(Mask.Planes[i] = (PLANEPTR)AllocRaster(Info->TabWidth,Info->TabHeight)))
GotIt = FALSE;
}
for(i = 0 ; GotIt && i < Info->Count ; i++)
{
if(!(Info->Tabs[i].BitMap = LTP_CreateBitMap(Info->TabWidth,Info->TabHeight,Depth,NULL,TRUE)))
GotIt = FALSE;
}
if(GotIt)
{
Depth = LTP_GetDepth(Screen->RastPort.BitMap);
if(!(Info->BitMap = LTP_CreateBitMap(gadget->Width,Info->TabHeight,Depth,Screen->RastPort.BitMap,FALSE)))
GotIt = FALSE;
}
if(GotIt)
{
struct TmpRas TmpRas;
LONG j,Len,Offset,Pos;
InitTmpRas(&TmpRas,Mask.Planes[1],RASSIZE(Info->TabWidth,Info->TabHeight));
RPort->TmpRas = &TmpRas;
RPort->BitMap = &Mask;
SetRast(RPort,0);
LTP_SetPens(RPort,1,0,JAM1);
DrawCap(RPort,0,0,Lean,Info->TabHeight,TRUE);
LTP_DrawLine(RPort,Lean,0,Info->TabWidth - (Lean + 1),0);
DrawCap(RPort,Info->TabWidth - Lean,0,Lean,Info->TabHeight,FALSE);
LTP_DrawLine(RPort,0,Info->TabHeight - 1,Info->TabWidth - 1,Info->TabHeight - 1);
Flood(RPort,1,Info->TabWidth / 2,Info->TabHeight / 2);
LTP_SetAPen(RPort,0);
for(i = 0 ; i < 2 ; i++)
{
for(j = 0 ; j < Info->Thick ; j++)
WritePixel(RPort,j,Info->TabHeight - 1 - i);
for(j = 0 ; j < Info->Thick ; j++)
WritePixel(RPort,Info->TabWidth - 1 - j,Info->TabHeight - 1 - i);
}
WaitBlit();
FreeRaster(Mask.Planes[1],Info->TabWidth,Info->TabHeight);
// *VERY* important; leaving a dead TmpRas around will
// cause problems with Text() later as Gfx may use
// RPort->TmpRas for buffering.
RPort->TmpRas = NULL;
Offset = (Width - Info->Thick * 5) / Info->Count;
while(Offset > 0 && Offset * (Info->Count - 1) + Info->TabWidth >= Width - Info->Thick * 5)
Offset--;
if(Offset > Info->TabWidth + Info->Thick)
Offset = Info->TabWidth + Info->Thick;
Pos = 2 * Info->Thick;
for(i = 0 ; i < Info->Count ; i++)
{
RPort->BitMap = Info->Tabs[i].BitMap;
Info->Tabs[i].Left = Pos;
Pos += Offset;
SetRast(RPort,Pens[BACKGROUNDPEN]);
LTP_SetAPen(RPort,Pens[SHINEPEN]);
for(j = 0 ; j < Info->Thick ; j++)
DrawCap(RPort,Info->Thick + j,0,Lean,Info->TabHeight,TRUE);
LTP_DrawLine(RPort,Info->Thick + Lean,0,Info->TabWidth - (Lean + 1) - Info->Thick,0);
LTP_SetAPen(RPort,Pens[SHADOWPEN]);
for(j = 0 ; j < Info->Thick ; j++)
DrawCap(RPort,Info->TabWidth - Lean - j - Info->Thick,0,Lean,Info->TabHeight,FALSE);
LTP_SetAPen(RPort,Pens[TEXTPEN]);
Len = strlen(Labels[i]);
LTP_PrintText(RPort,Labels[i],Len,(Info->TabWidth - TextLength(RPort,Labels[i],Len)) / 2,2);
}
Info->Mask = Mask.Planes[0];
Info->Offset = Offset;
Info->RPort.BitMap = Info->BitMap;
CloseFont(Font);
return((ULONG)gadget);
}
}
}
}
CloseFont(Font);
}
}
CoerceMethod(class,(Object *)gadget,OM_DISPOSE);
}
return(0);
}
STATIC ULONG
InputMethod(struct IClass *class,struct Gadget *gadget,struct gpInput *InputInfo)
{
TabInfo *Info = INST_DATA(class,gadget);
ULONG Result = GMR_MEACTIVE;
LONG x,y;
BOOL Done = FALSE;
x = InputInfo->gpi_Mouse.X;
y = InputInfo->gpi_Mouse.Y;
if(InputInfo->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE)
{
if(InputInfo->gpi_IEvent->ie_Code == MENUDOWN)
{
Result = GMR_NOREUSE;
Done = TRUE;
}
else
{
if(InputInfo->gpi_IEvent->ie_Code == SELECTUP)
{
Done = TRUE;
if(x >= 0 && x < gadget->Width && y >= 0 && y < gadget->Height)
{
Result = GMR_NOREUSE | GMR_VERIFY;
*InputInfo->gpi_Termination = Info->Current;
}
else
Result = GMR_NOREUSE;
}
}
}
if(Result == GMR_NOREUSE)
{
struct RastPort *RPort;
if(RPort = ObtainGIRPort(InputInfo->gpi_GInfo))
{
Info->Current = Info->Initial;
DoMethod((Object *)gadget,GM_RENDER,InputInfo->gpi_GInfo,RPort,GREDRAW_REDRAW);
ReleaseGIRPort(RPort);
}
}
if(!Done)
{
if(x >= 0 && x < gadget->Width && y >= 0 && y < gadget->Height)
{
LONG Index,i;
for(Index = -1, i = Info->Count - 1 ; i >= 0 ; i--)
{
if(x >= Info->Tabs[i].Left && x < Info->Tabs[i].Left + Info->TabWidth)
Index = i;
}
if(Index != Info->Current && Index != -1)
{
struct RastPort *RPort;
if(RPort = ObtainGIRPort(InputInfo->gpi_GInfo))
{
Info->Current = Index;
DoMethod((Object *)gadget,GM_RENDER,InputInfo->gpi_GInfo,RPort,GREDRAW_UPDATE);
ReleaseGIRPort(RPort);
}
}
}
}
return(Result);
}
STATIC ULONG
ActiveMethod(struct IClass *class,struct Gadget *gadget,struct gpInput *InputInfo)
{
TabInfo *Info = INST_DATA(class,gadget);
struct RastPort *RPort;
if(RPort = ObtainGIRPort(InputInfo->gpi_GInfo))
{
LONG Current,i;
LONG x;
x = InputInfo->gpi_Mouse.X;
for(Current = -1, i = Info->Count - 1 ; i >= 0 ; i--)
{
if(x >= Info->Tabs[i].Left && x < Info->Tabs[i].Left + Info->TabWidth)
Current = i;
}
Info->Initial = Info->Current;
if(Current != Info->Current && Current != -1)
{
Info->Current = Current;
DoMethod((Object *)gadget,GM_RENDER,InputInfo->gpi_GInfo,RPort,GREDRAW_UPDATE);
}
ReleaseGIRPort(RPort);
return(GMR_MEACTIVE);
}
else
return(GMR_NOREUSE);
}
STATIC ULONG
InactiveMethod(struct IClass *class,struct Gadget *gadget,struct gpGoInactive *InactiveInfo)
{
TabInfo *Info = INST_DATA(class,gadget);
struct RastPort *RPort;
LONG Index;
if(InactiveInfo->gpgi_Abort)
Index = Info->Initial;
else
Index = Info->Current;
if(RPort = ObtainGIRPort(InactiveInfo->gpgi_GInfo))
{
Info->Current = Index;
DoMethod((Object *)gadget,GM_RENDER,InactiveInfo->gpgi_GInfo,RPort,GREDRAW_REDRAW);
ReleaseGIRPort(RPort);
}
return(0);
}
BOOL
LTP_ObtainTabSize(struct IBox *Box,...)
{
va_list VarArgs;
struct TagItem *TagList,*Tag;
struct TextAttr *FontAttr;
struct DrawInfo *DrawInfo;
STRPTR *Labels;
LONG Count;
LONG SizeType;
BOOL Success;
Success = FALSE;
va_start(VarArgs,Box);
TagList = (struct TagItem *)VarArgs;
SizeType = GDOMAIN_NOMINAL;
FontAttr = NULL;
DrawInfo = NULL;
Labels = NULL;
while(Tag = NextTagItem(&TagList))
{
switch(Tag->ti_Tag)
{
case TIA_Labels:
Labels = (STRPTR *)Tag->ti_Data;
break;
case TIA_Font:
FontAttr = (struct TextAttr *)Tag->ti_Data;
break;
case TIA_DrawInfo:
DrawInfo = (struct DrawInfo *)Tag->ti_Data;
break;
case TIA_SizeType:
SizeType = Tag->ti_Data;
break;
}
}
Count = 0;
if(Labels)
{
while(Labels[Count])
Count++;
}
if(DrawInfo && FontAttr && Labels && Count)
{
struct TextFont *Font;
if(Font = OpenFont(FontAttr))
{
struct RastPort RastPort,*RPort = &RastPort;
LONG i,Len,MaxWidth;
LONG Lean,Thick;
InitRastPort(RPort);
SetFont(RPort,Font);
Box->Left = 0;
Box->Top = 0;
Box->Height = RPort->TxHeight + 11;
Lean = (TextLength(RPort,"O",1) + 1) / 2;
Thick = (DrawInfo->dri_Resolution.Y + DrawInfo->dri_Resolution.X - 1) / DrawInfo->dri_Resolution.X;
if(Thick < 1)
Thick = 1;
for(i = MaxWidth = 0 ; i < Count ; i++)
{
if((Len = TextLength(RPort,Labels[i],strlen(Labels[i]))) > MaxWidth)
MaxWidth = Len;
}
MaxWidth = 2 + (Lean + Thick - 1 + Thick + MaxWidth + Thick + Lean + Thick - 1) + 2;
if(SizeType == GDOMAIN_MINIMUM && Count > 1)
Box->Width = 2 * Thick + MaxWidth + (Count - 1) * (Thick * 4) + Thick * 3;
else
Box->Width = 2 * Thick + Count * (MaxWidth + Thick) + Thick * 2;
CloseFont(Font);
Success = TRUE;
}
}
va_end(VarArgs);
return(Success);
}
ULONG SAVE_DS ASM
LTP_TabClassDispatcher(REG(a0) struct IClass *class,REG(a2) Object *object,REG(a1) Msg msg)
{
switch(msg->MethodID)
{
case OM_NEW:
return(NewMethod(class,(struct Gadget *)object,(struct opSet *)msg));
case OM_UPDATE:
case OM_SET:
SetMethod(class,(struct Gadget *)object,(struct opSet *)msg);
break;
case GM_RENDER:
return(RenderMethod(class,(struct Gadget *)object,(struct gpRender *)msg));
case GM_HITTEST:
return(GMR_GADGETHIT);
case GM_GOINACTIVE:
return(InactiveMethod(class,(struct Gadget *)object,(struct gpGoInactive *)msg));
case GM_HANDLEINPUT:
return(InputMethod(class,(struct Gadget *)object,(struct gpInput *)msg));
case GM_GOACTIVE:
return(ActiveMethod(class,(struct Gadget *)object,(struct gpInput *)msg));
case OM_DISPOSE:
DisposeMethod(class,(struct Gadget *)object,msg);
// Falls down through to the default case...
}
return(DoSuperMethodA(class,object,msg));
}
#endif /* DO_TAB_KIND */